﻿using Common.EF.Structs;
using Common.Infrastructure;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Common.EF.Utils
{
    public static class EntityInitUtils
    {
        public static void Init(IConfiguration configuration)
        {
            DoInitEntityType(configuration);
        }

        private static void DoInitEntityType(IConfiguration configuration)
        {
            var files = System.IO.Directory.GetFiles(System.AppContext.BaseDirectory, "*.Data.dll");
            if (files != null && files.Any())
            {
                foreach (var file in files)
                {
                    var assembly = Assembly.LoadFrom(file);
                    if (assembly != null)
                    {
                        var types = assembly.GetTypes();
                        foreach (var t in types)
                        {
                            if (!t.IsSubclassOf(typeof(EntityBase)))
                            {
                                continue;
                            }

                            EntityType entityType = new EntityType
                            {
                                Name = t.Name,
                                Type = t
                            };
                            EntityTypeManager.AddEntityType(entityType);
                            EntityConfig entityConfig = new EntityConfig
                            {
                                Name = t.Name,
                                ContextType = (EntityConfigContextTypeEnum)LibSysUtils.ToInt(configuration["DefaultContextType"])
                            };

                            var pp = GetAttributeByType<EntityContextTypeAttribute>(t);
                            if (pp != null)
                            {
                                entityConfig.ContextType = (EntityConfigContextTypeEnum)pp.ContextType;
                                if (pp.SpecialContextCodes != null)
                                {
                                    entityConfig.AllowContexts.AddRange(pp.SpecialContextCodes);
                                }
                            }

                            foreach (var p in t.GetProperties())
                            {
                                bool isAdd = false;
                                var fieldConfig = new EntityFieldConfig
                                {
                                    Name = p.Name
                                };
                                var iattr = GetAttributeByProperty<EntityFieldIndexAttribute>(p);
                                if (iattr != null)
                                {
                                    isAdd = true;
                                    fieldConfig.IsUnique = iattr.IsUnique;
                                    fieldConfig.IsUniqueByOrg = iattr.IsUniqueByOrg;
                                }

                                var iattrCheck = GetAttributeByProperty<EntityFieldCheckUniqueAttribute>(p);
                                if (iattrCheck != null)
                                {
                                    isAdd = true;
                                    fieldConfig.IsUnique = true;
                                    if (iattrCheck.UniqueFields != null && iattrCheck.UniqueFields.Any(t => t == "org_id"))
                                    {
                                        fieldConfig.IsUniqueByOrg = true;
                                    }
                                }

                                if (isAdd)
                                {
                                    entityConfig.AddFieldEntityConfig(fieldConfig);
                                }
                            }

                            EntityConfigManager.AddEntityConfig(entityConfig);
                        }
                    }
                }
            }
        }

        private static T GetAttributeByProperty<T>(PropertyInfo property) where T : Attribute
        {
            T attr = null;
            object[] attrs = property.GetCustomAttributes(typeof(T), true);
            if (attrs.Length == 1)
            {
                attr = (T)attrs[0];
            }

            return attr;
        }

        private static T GetAttributeByType<T>(Type type) where T : Attribute
        {
            T attr = null;
            object[] attrs = type.GetCustomAttributes(typeof(T), true);
            if (attrs.Length == 1)
            {
                attr = (T)attrs[0];
            }

            return attr;
        }
    }
}
